package com.ruoyi.framework.interceptor;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.RsaUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author 王先亮
 * createTime: 2020/6/18.
 * description: 打印
 */
@Component
public class RequestNonceInterceptor implements HandlerInterceptor {

    /**
     * nonce校验间隔秒数
     */
    @Value("${ruoyi.nonceCheckSeconds}")
    private Integer nonceCheckSeconds;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //如果是post和put
        String method = request.getMethod();
        if (method.equals("POST") || method.equals("PUT")) {
            //校验
            String checkNonce = request.getHeader("Check-Nonce");
            String checkTime = request.getHeader("Check-Time");

            //为空时，返回
            if (StrUtil.isBlank(checkNonce) || StrUtil.isBlank(checkTime)) {
                return renderError(response, "nonce校验失败，校验符为空。");
            }

            //时间
            long seconds = DateUtil.between(new Date(Long.parseLong(checkTime)), new Date(), DateUnit.SECOND);
            if (Math.abs(seconds) > nonceCheckSeconds) {
                return renderError(response, "请求时间间隔过长。");
            }

            //匹配性教研
            String nonceTime = RsaUtils.decryptByPrivateKey(checkNonce);
            if (!nonceTime.equals(checkTime)) {
                return renderError(response, "nonce校验失败，校验字符无效。");
            }

            //同一nonce无法重复提交
            RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
            String cacheKey = "checkNonce:" + checkNonce;
            if (redisCache.hasKey(cacheKey)) {
                return renderError(response, "nonce校验失败，请勿重复提交请求。");
            }

            //存储key 用于校验重复提交
            redisCache.setCacheObject(cacheKey, checkTime, nonceCheckSeconds, TimeUnit.SECONDS);
        }
        return true;
    }

    public boolean renderError(HttpServletResponse response, String msg) {
        AjaxResult ajaxResult = AjaxResult.error(msg);
        ServletUtils.renderString(response, JSON.toJSONString(ajaxResult));
        return false;
    }
}
